package idp.honeytracks;



import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;

public class JSONParser {	

	//this is a json results file
	final String filePath = "C:\\Users\\User\\Desktop\\idp\\json_smal_march.txt";
	
	
	//this is the output file for arff from json
	final String resultFile = "building_arff.arff";
	List<String> list_values = new ArrayList<String>();
	List<String> list_keys = new ArrayList<String>();
	List<String> countries = new ArrayList<String>();
	
	//number of class attribute in map of keys
	int num_revenue_class;
	
	public int getNum_revenue_class() {
		return num_revenue_class;
	}

	/*
	 * void calls the private methods of the class
	 * in order to parse the json file 
	 * and write the result into arff
	 */
	public void parseJSON() throws Exception{
		InputStream input = this.getClass().getResourceAsStream("urls.txt");
		BufferedReader reader = new BufferedReader(new InputStreamReader(input,
				"UTF-8"));
		String line, fetch_url="";
		
		while ((line = reader.readLine()) != null) {
				fetch_url = line;			
			break;
		}
		
		
		BufferedReader br = new BufferedReader(new FileReader(this.filePath));
			
		
		
		
		byte[] buffer2 = new byte[(int) new File(this.filePath).length()];
		FileInputStream f2 = new FileInputStream(this.filePath);
		f2.read(buffer2);
		String data = new String(buffer2);
		
		JsonElement je = new JsonParser().parse(data);
		JsonObject jo = je.getAsJsonObject();
		createMapFromJsonObjectForValues(jo);	    
		writeToARFFWithUnknownKeys(list_keys, list_values, countries);
	}
	
	private void createMapFromJsonObjectForValues(JsonObject jo) {

		for (Entry<String, JsonElement> entry : jo.entrySet()) {

			JsonElement value = entry.getValue();
			Object value_from_json = getValueFromJsonElement(value);
			if (value_from_json instanceof List<?>){
				parseForArff(value_from_json);
			}
		
		}
	}
	
	
	/*
	 * write the results from parsing to arff file
	 */
	public  void writeToARFFWithUnknownKeys(List<String> properties, List<String> data, List<String> countries){
		try{
		FileWriter fstream = new FileWriter(resultFile, false);
		BufferedWriter out = new BufferedWriter(fstream);
		out.write("@RELATION game");
		out.newLine();
		for (String str: properties){
			out.write("@ATTRIBUTE " +str);
			if (!str.equals("GenderIsMale") && !str.equals("countryId")){
				out.write(" NUMERIC");
			}else if (str.equals("GenderIsMale")){
				out.write(" {0,1,2}");
			}else if (str.equals("countryId")){
				out.write(" {");
				for (int j=0; j<countries.size();j++){
					out.write(countries.get(j));
					if (j!=countries.size()-1) 
						out.write(",");
				}	
				out.write("}");	
			}
			out.newLine();
		}
		out.write("@DATA");
		out.newLine();
		for (String value : data){
			out.write(value);
			out.newLine();
		}
		out.flush();
		out.close();
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}
	
	/*
	 * 
	 */
	private void parseForArff(Object value_from_json) {
		list_keys = new ArrayList<String>();
			List<Object> result_value = (List<Object>) value_from_json;
			int j=0;
			countries = new ArrayList<String>();
			for (Object obj : result_value){
				
				//{UsageFIGHTFeatureTypeAverage=0.0500, VirtualCurrencyValueAverage=null}
				//- this is object representation format
				String obj_representation = obj.toString();
				String[] arr = obj_representation.split(",");
				String cur_value_str="";
				String cur_key="";
				for (int i=0; i< arr.length; i++){
					cur_key  = arr[i].substring(1, arr[i].indexOf('='));
					if (j==0 && !list_keys.contains(cur_key)){
						//here hard-coded name of class attribute
						//needed the check to get the number of this attribute in arff-file
						if (cur_key.equals("RevenueTotal")){
							num_revenue_class=list_keys.size()+1;
						}
						list_keys.add(new String(cur_key));
						
					}		
					
					if (i != arr.length-1){
						String cur_key_value = arr[i].substring(arr[i].indexOf('=')+1); 
						
						if (cur_key_value.equals("null"))
							cur_key_value = "0.0000";
						cur_value_str  += (cur_key_value+",");
						if (cur_key.equals("countryId")&&
								!countries.contains(cur_key_value)){
							countries.add(cur_key_value);
						}
					}else{
						cur_value_str += arr[i].substring(arr[i].indexOf('=')+1, arr[i].indexOf('}'));
					}				
				}
				j=1;			
				list_values.add(new String(cur_value_str));
			}
		}
	
	private Map<String, Object> createMapFromJsonObject(JsonObject jo, boolean check) {
		Map<String, Object> map = new HashMap<String, Object>();
		for (Entry<String, JsonElement> entry : jo.entrySet()) {
			String key = entry.getKey();
			JsonElement value = entry.getValue();
			map.put(key, getValueFromJsonElement(value));

		}
		return map;
	}
	

	private Object getValueFromJsonElement(JsonElement je) {
		if (je.isJsonObject()) {
			return createMapFromJsonObject(je.getAsJsonObject(), false);
		} else 
		if (je.isJsonArray()) {
			JsonArray array = je.getAsJsonArray();
			List<Object> list = new ArrayList<Object>(array.size());
			for (JsonElement element : array) {
				Object value =getValueFromJsonElement(element);
				list.add(value);
			}
			return list;
		} else if (je.isJsonNull()) {
			return null;
		} else // must be primitive
		{
			JsonPrimitive p = je.getAsJsonPrimitive();
			if (p.isBoolean())
				return p.getAsBoolean();
			if (p.isString())
				return p.getAsString();
			// else p is number, but don't know what kind
			String s = p.getAsString();
			try {
				return new BigInteger(s);
			} catch (NumberFormatException e) {
				// must be a decimal
				return new BigDecimal(s);
			}
		}
	}

}
